package com.fjec.paid.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fjec.common.exception.BizException;
import com.fjec.common.util.DateUtil;
import com.fjec.common.util.JsonUtil;
import com.fjec.common.util.SequenceIdGenerator;
import com.fjec.common.ys.PaidHelper;
import com.fjec.common.ys.YsProperties;
import com.fjec.paid.entity.BizDistribution;
import com.fjec.paid.entity.BizDistributionDetail;
import com.fjec.paid.entity.BizDistributionLog;
import com.fjec.paid.entity.BizYsPayment;
import com.fjec.paid.feign.MarketClient;
import com.fjec.paid.mapper.BizDistributionMapper;
import com.fjec.paid.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 012.分账表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2020-11-09
 */
@Service
public class BizDistributionServiceImpl extends ServiceImpl<BizDistributionMapper, BizDistribution> implements IBizDistributionService {

    @Resource
    private BizDistributionMapper mapper;

    @Resource
    private IBizDistributionDetailService bizDistributionDetailService;

    @Resource
    private IBizDistributionLogService bizDistributionLogService;

    @Resource
    private IBizYsPaymentService bizYsPaymentService;

    @Autowired
    private PaidHelper paidHelper;

    @Autowired
    private SequenceIdGenerator idGenerator;

    @Autowired
    private YsProperties ysProperties;

    @Autowired
    private MarketClient marketClient;

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void doDivide(BizDistribution dist) {
        String outTradeNo = dist.getOutTradeNo();
        String payeeUserCode = dist.getPayeeUsercode();
        Integer amount = dist.getTotalAmount();
        String totalAmount = String.valueOf(amount.doubleValue() / 100);
        // 分账明细
        List<Map<String, Object>> divList = new ArrayList<>();
        List<BizDistributionDetail> distributionDetails = bizDistributionDetailService.list(
                new QueryWrapper<BizDistributionDetail>().eq("DistId", dist.getId()));
        distributionDetails.forEach(dd -> {
            Map<String, Object> div = new HashMap<>();
            div.put("division_mer_usercode", dd.getDivisionMerUsercode());
            div.put("div_ratio", dd.getDivRatio());
            String isChargeFee;
            if (dd.getIsChargeFee() == 1)
                isChargeFee = "01";
            else
                isChargeFee = "02";
            div.put("is_chargeFee", isChargeFee);
            divList.add(div);
        });

        try {
            Map<String, Object> resMap = paidHelper.divide(outTradeNo, payeeUserCode, totalAmount, divList);
            Map<String, Object> bizResponse = MapUtils.getMap(resMap, "ysepay_single_division_online_accept_response");
            String code = MapUtils.getString(bizResponse,"code");
            String msg = MapUtils.getString(bizResponse, "msg");
            String returnCode = MapUtils.getString(bizResponse, "returnCode");

            if (code.equals("10000") && msg.equals("Success")) {
//                0000	分账推送成功，已登记
//                9999	分账登记失败
                if (returnCode.equals("0000")) {
                    // 分账登记成功
                    dist.setDistStatus(1);
                    // 如该笔订单存在退款，发送退款请求
//                    List<Map<String, Object>> refundInfo = bizOrderRefundService
//                            .getRefundInfo(dist.getPaymentId(), 10, 0);
//                    if (refundInfo.size() > 0)
//                        bizOrderRefundService.doRefund(refundInfo.get(0));

                } else if (returnCode.equals("9999")) {
                    // 分账登记失败
                    dist.setDistStatus(3);
                }

            } else {
                // 发起分账请求失败
                dist.setDistStatus(3);
            }

            // 分账log表
            BizDistributionLog distributionLog = new BizDistributionLog();
            distributionLog.setDistId(dist.getId());
            distributionLog.setYsResponse(JsonUtil.toJson(bizResponse));
            distributionLog.setCreateTime(DateUtil.nowLdt());
            bizDistributionLogService.save(distributionLog);

        } catch (Exception e) {
            // 如网络不通、银盛服务器内部错误等
            dist.setDistStatus(0);
        }

        this.updateById(dist);
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public int savePhyDivideBatch(List<Map<String, Object>> ordersToDivide) {
        List<BizDistribution> distributions = new ArrayList<>();
        List<BizDistributionDetail> distributionDetails = new ArrayList<>();
        // 获取所有银盛支付信息
        List<Long> paymentIds = ordersToDivide.stream()
                .map(m -> MapUtils.getLong(m, "paymentId"))
                .collect(Collectors.toList());
        List<BizYsPayment> ysPayments = bizYsPaymentService.list(new QueryWrapper<BizYsPayment>()
                .in("PaymentId", paymentIds));

        LocalDateTime now = DateUtil.nowLdt();
        ordersToDivide.forEach(m -> {
            Long paymentId = MapUtils.getLong(m, "paymentId");

            Optional<BizYsPayment> op = ysPayments.stream()
                    .filter(p -> p.getPaymentId().equals(paymentId))
                    .findFirst();
            if (op.isPresent()) {
                BizYsPayment ysPayment = op.get();
                Long orderId = MapUtils.getLong(m, "orderId");
                Integer totalAmount = MapUtils.getInteger(m, "totalAmount");
                String userCode = MapUtils.getString(m, "userCode");
                Double divRatio = MapUtils.getDoubleValue(m, "divRatio");

                // biz_distribution
                BizDistribution distribution = BizDistribution.builder()
                        .id(idGenerator.nextId())
                        .paymentId(paymentId)
                        .outTradeNo(ysPayment.getOutTradeNo())
                        .payeeUsercode(userCode)
                        .totalAmount(totalAmount)
                        .sysFlag("DD")
                        .divisionMode("01")
                        .distStatus(0)
                        .createTime(now)
                        .build();
                // biz_distribution_detail
                BizDistributionDetail shopDistributionDetail = BizDistributionDetail.builder()
                        .distId(distribution.getId())
                        .orderId(orderId)
                        .divisionMerUsercode(userCode)
                        .divRatio(new BigDecimal(1 - divRatio))
                        .isChargeFee(2)
                        .createTime(now)
                        .build();
                BizDistributionDetail platformDistributionDetail = BizDistributionDetail.builder()
                        .distId(distribution.getId())
                        .orderId(orderId)
                        .divisionMerUsercode(ysProperties.getSellerId())
                        .divRatio(new BigDecimal(divRatio))
                        .isChargeFee(1)
                        .createTime(now)
                        .build();

                distributions.add(distribution);
                distributionDetails.add(shopDistributionDetail);
                distributionDetails.add(platformDistributionDetail);

            }
        });

        boolean d = this.saveBatch(distributions);
        boolean dd = bizDistributionDetailService.saveBatch(distributionDetails);
        if (d && dd)
            return 0;
        else
            return -1;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public int saveServDivideBatch(List<Map<String, Object>> ordersToDivide) {
        List<BizDistribution> distributions = new ArrayList<>();
        List<BizDistributionDetail> distributionDetails = new ArrayList<>();
        // 获取所有银盛支付信息
        List<Long> paymentIds = ordersToDivide.stream()
                .map(m -> MapUtils.getLong(m, "paymentId"))
                .collect(Collectors.toList());
        List<BizYsPayment> ysPayments = bizYsPaymentService.list(new QueryWrapper<BizYsPayment>()
                .in("PaymentId", paymentIds));

        LocalDateTime now = DateUtil.nowLdt();
        ordersToDivide.forEach(m -> {
            Long paymentId = MapUtils.getLong(m, "paymentId");

            Optional<BizYsPayment> op = ysPayments.stream()
                    .filter(p -> p.getPaymentId().equals(paymentId))
                    .findFirst();
            if (op.isPresent()) {
                BizYsPayment ysPayment = op.get();
                Long orderId = MapUtils.getLong(m, "orderId");
                Integer totalAmount = MapUtils.getInteger(m, "totalAmount");

                // biz_distribution
                BizDistribution distribution = BizDistribution.builder()
                        .id(idGenerator.nextId())
                        .paymentId(paymentId)
                        .outTradeNo(ysPayment.getOutTradeNo())
                        .payeeUsercode(ysProperties.getSellerId())
                        .totalAmount(totalAmount)
                        .sysFlag("DD")
                        .divisionMode("01")
                        .distStatus(0)
                        .createTime(now)
                        .build();
                // biz_distribution_detail
                BizDistributionDetail platformDistributionDetail = BizDistributionDetail.builder()
                        .distId(distribution.getId())
                        .orderId(orderId)
                        .divisionMerUsercode(ysProperties.getSellerId())
                        .divRatio(new BigDecimal(1.0))
                        .isChargeFee(1)
                        .createTime(now)
                        .build();

                distributions.add(distribution);
                distributionDetails.add(platformDistributionDetail);

            }
        });

        boolean d = this.saveBatch(distributions);
        boolean dd = bizDistributionDetailService.saveBatch(distributionDetails);
        if (d && dd)
            return 1;
        else
            return -1;
    }

    @Override
    public List<BizDistribution> getDividing(int limit) {
        return mapper.getDividing(limit);
    }

    /**
     * 分账查询
     * @param dist
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void doQuery(BizDistribution dist) {
        String payeeUserCode = dist.getPayeeUsercode();
        String outTradeNo = dist.getOutTradeNo();

        try {
            Map<String, Object> resMap = paidHelper.queryDivide(payeeUserCode, outTradeNo);
            Map<String, Object> infoMap = MapUtils.getMap(resMap, "ysepay_single_division_online_query_response");
            String code = MapUtils.getString(infoMap, "code");
            String msg = MapUtils.getString(infoMap, "msg");
            String division_status_code = MapUtils.getString(infoMap, "division_status_code");

            if (code.equals("10000") && msg.equals("Success")) {
//                01	受理成功(登记成功)
//                02	预分账成功(已拆分，待结算)
//                00	分账成功
//                03	无需分账
//                99	分账失败
                if (division_status_code.equals("00")) {
                    // 分账成功
                    dist.setDistStatus(2);
                    // 写入双方分账到账金额
                    List<Map<String, Object>> distAmounts = (List<Map<String, Object>>) infoMap.get("detailResults");
                    distAmounts.forEach(d -> {
                        String userCode = MapUtils.getString(d, "division_mer_usercode");
                        String amount = MapUtils.getString(d, "division_amount");
                        if (userCode.equals(ysProperties.getSellerId()))
                            dist.setPlatformDivision(amount);
                        else
                            dist.setShopDivision(amount);
                    });
                    String accountTime = MapUtils.getString(infoMap, "update_time");
                    dist.setAccountTime(accountTime);
                    // 更新订单表 分账状态为已到账2
                    int c = marketClient.setDistStatusAccounted(dist.getPaymentId());
                    if (c != 0)
                        throw new BizException(null, null);

                } else if (division_status_code.equals("99")) {
                    // 分账失败
                    dist.setDistStatus(3);
                } else {
                    // 仍处在分账中
                    dist.setDistStatus(1);
                }
                dist.setUpdateTime(DateUtil.nowLdt());
                this.updateById(dist);
            }
        } catch (Exception e) {
            // do nothing
        }
    }

    @Override
    public int ysDeliver(Long paymentId) {
        BizYsPayment bizYsPayment = bizYsPaymentService.getOne(new QueryWrapper<BizYsPayment>()
                .eq("PaymentId", paymentId));
        String outTradeNo = bizYsPayment.getOutTradeNo();
        String tradeNo = bizYsPayment.getTradeNo();
        String shopDate = bizYsPayment.getShopdate();

//        {"code":"10000","msg":"Success","out_trade_no":"20201215604675871822913539",
//                "trade_no":"01O201215242649984","trade_status":"WAIT_BUYER_CONFIRM_GOODS"}
        try {
            Map<String, Object> resMap = paidHelper.ysDeliver(outTradeNo, shopDate, tradeNo);
            Map<String, Object> infoMap = MapUtils.getMap(resMap, "ysepay_online_trade_delivered_response");
            String code = MapUtils.getString(infoMap, "code");
            String msg = MapUtils.getString(infoMap, "msg");
            String tradeStatus = MapUtils.getString(infoMap, "trade_status");
            if (code.equals("10000") && msg.equals("Success") && tradeStatus.equals("WAIT_BUYER_CONFIRM_GOODS"))
                return 1;

        } catch (Exception e) {
            return -1;
        }
        return 1;
    }

    @Override
    public int ysSign(Long paymentId) {
        BizYsPayment bizYsPayment = bizYsPaymentService.getOne(new QueryWrapper<BizYsPayment>()
                .eq("PaymentId", paymentId));
        String outTradeNo = bizYsPayment.getOutTradeNo();
        String tradeNo = bizYsPayment.getTradeNo();
        String shopDate = bizYsPayment.getShopdate();

//        {"code":"10000","msg":"Success","out_trade_no":"20201215604675871822913539",
//                "trade_no":"01O201215242649984","trade_status":"TRADE_SUCCESS"}
        try {
            Map<String, Object> resMap = paidHelper.ysSign(outTradeNo, shopDate, tradeNo);
            Map<String, Object> infoMap = MapUtils.getMap(resMap, "ysepay_online_trade_confirm_response");
            String code = MapUtils.getString(infoMap, "code");
            String msg = MapUtils.getString(infoMap, "msg");
            String tradeStatus = MapUtils.getString(infoMap,"trade_status");
            if (code.equals("10000") && msg.equals("Success") && tradeStatus.equals("TRADE_SUCCESS"))
                return 1;
        } catch (Exception e) {
            return -1;
        }
        return 1;
    }
}
